#!/usr/bin/env node
'use strict'

const path = require('path')
const fs = require('fs')
const XLSX = require('xlsx')

const Pzip = require('pizzip')
const Docxtemplater = require('docxtemplater')
const expressions = require('docxtemplater/expressions.js')
const log = require('./utils/log')
const pkg = require('./package.json')
const pathExistsSync = require('path-exists').sync
const { Command } = require('commander')
const program = new Command()
const COMMANDS = {
  EXECL_TO_JOSN: 'jsonbyxlsx',
  CREATE_BY_JSON: 'createbyjson',
  CREATE_BY_XLSX: 'createbyxlsx',
}

function main() {
  registerCommands()
}
main()
function registerCommands() {
  program
    .name(Object.keys(pkg.bin)[0])
    .command(COMMANDS.EXECL_TO_JOSN)
    .description('将xlsx文件转换为json文件')
    .requiredOption('-i, --input <file>', '输入一个.xlsx excel的文件路径')
    .requiredOption('-s, --sheetName <name>', '输入一个sheet名')
    .requiredOption('-o, --output <file>', '输出 JSON 文件')
    .action(tojsonAction)

  program
    .command(COMMANDS.CREATE_BY_JSON)
    .description('根据json文件数据渲染word模板并输出')
    .requiredOption('-t, --template <file>', '输入word template文件的路径')
    .requiredOption('-j, --json <jsonPath>', '输入json文件的路径')
    .requiredOption('-o, --output <file>', '输出 目标word文件路径')
    .action(createByJsonAction)

  program
    .command(COMMANDS.CREATE_BY_XLSX)
    .description('根据json文件数据渲染word模板并输出')
    .requiredOption('-t, --template <file>', '输入word template文件的路径')
    .requiredOption('-x, --xlsxFile <xlsxPath>', '输入excel文件的路径')
    .requiredOption('-s, --sheetname  <name>', '输入excel文件sheet的名称')
    .requiredOption('-o, --output <file>', '输出目标word文件路径')
    .requiredOption('-d, --datakey <key>', '渲染对象的属性值')
    .action(createByXlsxAction)

  program.on('command:*', obj => {
    log.warn('未知命令：', `${obj[0]}不是一个可执行的命令\n`)
    log.info('帮助命令：-h --help')
    program.outputHelp()
  })

  program.parse(process.argv)
}

function tojsonAction({ input, sheetName, output }) {
  try {
    if (!pathExistsSync(input)) {
      log.error(`输入路径${input}的excel文件不存在`)
      process.exit(1)
    }
    const json = josnByXlsx(input, sheetName)
    fs.writeFileSync(output, JSON.stringify(json))
    log.info(`创建成功，输出路径为${output}`)
  } catch (error) {
    log.error(error.message)
  }
}

function createByJsonAction({ template, json, output }) {
  try {
    if (!pathExistsSync(template)) {
      log.error(`输入路径${template}的模板文件不存在`)
      process.exit(1)
    }
    if (!pathExistsSync(json)) {
      log.error(`输入路径${json}的json数据文件不存在`)
      process.exit(1)
    }
    const data = require(json)
    renderAndWrite(template, data, output)
    log.info(`创建成功，输出路径为${output}`)
  } catch (error) {
    log.error(error.message)
  }
}

function createByXlsxAction({
  template,
  xlsxFile,
  sheetname,
  output,
  datakey,
}) {
  console.log("args", template, xlsxFile, sheetname, output, datakey);
  try {
    if (!pathExistsSync(template)) {
      log.error(`输入路径${template}的模板文件不存在`)
      process.exit(1)
    }
    if (!pathExistsSync(xlsxFile)) {
      log.error(`输入路径${xlsxFile}的xlsx文件不存在`)
      process.exit(1)
    }
    const json = josnByXlsx(xlsxFile, sheetname)
    const data = { [datakey]: json }
    renderAndWrite(template, data, output)
    log.info(`创建成功，输出路径为${output}`)
  } catch (error) {
    log.error(error.message)
  }
}

function renderAndWrite (template, data, output) {
  const context = fs.readFileSync(template, 'binary')
  const zip = new Pzip(context)
  const doc = new Docxtemplater(zip, {
    parser: expressions,
    linebreaks: true,
  })
  doc.render(data)
  const generatedDocx = doc.getZip().generate({ type: 'nodebuffer' })
  fs.writeFileSync(output, generatedDocx)
}

function josnByXlsx(file, sheetName) {
  const workbook = XLSX.readFile(file)
  const worksheet = workbook.Sheets[sheetName]
  return XLSX.utils.sheet_to_json(worksheet)
}

/**
 *spawn 封装windows和unix系统差异,参考http://nodejs.cn/api/child_process.html#spawning-bat-and-cmd-files-on-windows
 windows系统是通过cmd执行
 */
function spawn(command, args, options) {
  const isWin32 = process.platform === 'win32'
  const cmd = isWin32 ? 'cmd.exe' : command
  //"/c"参数是cmd的一个参数,表示执行完cmd命令后关闭
  const _args = isWin32 ? ['/c'].concat(command, args) : args
  const spawn = require('child_process').spawn
  return spawn(cmd, _args, options || {})
}

module.exports = main
